<template>
  <div :id="mapId" class="map h-100">
    <div class="map-switcher">
      <el-radio-group v-model="mapType" size="mini">
        <el-radio-button label="vector">矢量图</el-radio-button>
        <el-radio-button label="image">影像图</el-radio-button>
        <el-radio-button label="terrain">地形图</el-radio-button>
      </el-radio-group>
    </div>
    <div class="map-layer">
      <el-radio-group v-model="baseLayerMode" size="mini">
        <el-radio-button label="google">google</el-radio-button>
        <el-radio-button label="amap">高德</el-radio-button>
        <el-radio-button label="tdt">天地图</el-radio-button>
        <el-radio-button label="arcgis">arcgis</el-radio-button>
      </el-radio-group>
    </div>
  </div>
</template>
<script>
import { Common } from "cby.assist";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ as XYZSource, Vector as VectorSource } from "ol/source";
import TileGrid from "ol/tilegrid/TileGrid";
import { ScaleLine, FullScreen } from "ol/control";
const tileGrid = new TileGrid({
  origin: [-20037225, 20037190],
  resolutions: [
    156543.03392804097, 78271.51696402048, 39135.75848201024, 19567.87924100512,
    9783.93962050256, 4891.96981025128, 2445.98490512564, 1222.99245256282,
    611.49622628141, 305.748113140705, 152.8740565703525, 76.43702828517625,
    38.21851414258813, 19.109257071294063, 9.554628535647032, 4.777314267823516,
    2.388657133911758, 1.194328566955879, 0.5971642834779395,
    // 0.29858214173896974,
    // 0.14929107086948487,
  ],
});
export default {
  props: {
    option: {
      type: Object,
      default() {
        return {};
      },
    },
  },
  data() {
    return {
      mapId: Common.uuid(),
      map: null,
      mapType: "vector",
      vectorLayer: null, // 矢量图层
      vectorMarkLayer: null, // 矢量标注图层
      imageLayer: null, // 影像图层
      imageMarkLayer: null, // 影像标注图层
      terrainLayer: null, // 天地图图层
      terrainMarkLayer: null, // 天地图标注图层
      districtLayer: null,
      timer: null,
      baseLayerMode: "google", // 地图模式
    };
  },
  watch: {
    mapType(type) {
      // 重置所有图层
      if (this.vectorLayer) {
        this.vectorLayer.setVisible(false);
      }
      if (this.vectorMarkLayer) {
        this.vectorMarkLayer.setVisible(false);
      }
      if (this.imageLayer) {
        this.imageLayer.setVisible(false);
      }
      if (this.imageMarkLayer) {
        this.imageMarkLayer.setVisible(false);
      }
      if (this.terrainLayer) {
        this.terrainLayer.setVisible(false);
      }
      if (this.terrainMarkLayer) {
        this.terrainMarkLayer.setVisible(false);
      }
      if (type == "vector") {
        if (this.vectorLayer) {
          this.vectorLayer.setVisible(true);
        }
        if (this.vectorMarkLayer) {
          this.vectorMarkLayer.setVisible(true);
        }
      } else if (type == "image") {
        if (this.imageLayer) {
          this.imageLayer.setVisible(true);
        }
        if (this.imageMarkLayer) {
          this.imageMarkLayer.setVisible(true);
        }
      } else if (type == "terrain") {
        if (this.terrainLayer) {
          this.terrainLayer.setVisible(true);
        }
        if (this.terrainMarkLayer) {
          this.terrainMarkLayer.setVisible(true);
        }
      }
    },
    baseLayerMode(type) {
      // 切换时先把原来的地图图层去掉
      const oldLayers = this.map.getAllLayers();
      oldLayers.forEach((i) => {
        this.map.removeLayer(i);
      });
      let newLayers = [];
      if (type === "google") {
        newLayers = this.getGoogleLayers();
      } else if (type === "amap") {
        newLayers = this.getAmapLayers();
      } else if (type === "tdt") {
        newLayers = this.getTdtLayers();
      } else if (type === "arcgis") {
        newLayers = this.getMapLayers();
      }
      newLayers.forEach((i) => {
        this.map.addLayer(i);
      });
      this.mapType = "vector"
    },
  },
  mounted() {
    // 实例map对象加载地图
    // this.map = new Map({
    //   // 地图容器div的ID
    //   target: "",
    //   // 地图容器中加载的图层
    //   layers: [
    //     new TileLayer({
    //       source: "",
    //     }),
    //   ],
    //   // 地图视图设置
    //   view: new View({
    //     // 地图初始中心点
    //     center: [],
    //     // 地图初始显示级别
    //     zoom: 2,
    //   }),
    // });
    this.init(this.option);
    this.resize();
    this.$emit("mapcreated", this.map);
  },
  destroyed() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
  },
  methods: {
    init(option = {}) {
      option.target = this.mapId; // 地图容器的id
      // 地图视图设置
      if (!option.view) {
        option.view = new View({
          center: [11584557, 3588342],
          zoom: 12,
        });
      }
      if (option.tools == false) {
        this.tools = false;
      }
      // 地图容器中加载的图层
      if (!option.layers || !option.layers.length) {
        if (this.option.baseLayerMode) {
          this.baseLayerMode = this.option.baseLayerMode;
        }
        if (this.baseLayerMode == "google") { // 加载google底图
          option.layers = this.getGoogleLayers();
        } else if (this.baseLayerMode == "tdt") { // 加载天地图底图
          option.layers = this.getTdtLayers();
        } else if (this.baseLayerMode == "amap") { // 加载高德地图底图
          option.layers = this.getAmapLayers();
        } else {
          option.layers = this.getMapLayers(); // 加载arcgis底图
        }
        if (this.option.mapType) {
          this.mapType = this.option.mapType;
        }
      }
      if (!option.controls) {
        option.controls = [new ScaleLine()];
      }
      this.map = new Map(option);
      return this.map;
    },
    getGoogleLayers() {
      this.vectorLayer = this.googleLayer("m");
      this.imageLayer = this.googleLayer("y", { visible: false });
      this.terrainLayer = this.googleLayer("p", { visible: false });
      return [this.vectorLayer, this.imageLayer, this.terrainLayer];
    },
    googleLayer(type, opt = {}) {
      return new TileLayer(
        Object.assign(
          {
            source: new XYZSource({
              // url: `http://mt{0-3}.google.cn/vt/lyrs=${type}@142&hl=zh-CN&gl=cn&s=Galil&x={x}&y={y}&z={z}`,
              url: `https://gac-geo.googlecnapps.cn/maps/vt?lyrs=${type}&gl=CN&x={x}&y={y}&z={z}`,
            }),
          },
          opt
        )
      );
    },
    getTdtLayers() {
      this.vectorLayer = this.tdtLayer({
        type: "vec_w",
        tileGrid,
      });
      this.vectorMarkLayer = this.tdtLayer({
        type: "cva_w",
        tileGrid,
      });
      this.imageLayer = this.tdtLayer(
        { type: "img_w", tileGrid },
        { visible: false }
      );
      this.imageMarkLayer = this.tdtLayer(
        { type: "cia_w", tileGrid },
        { visible: false }
      );
      const terrainTileGrid = new TileGrid({
        origin: [-20037225, 20037190],
        resolutions: [
          156543.03392804097, 78271.51696402048, 39135.75848201024,
          19567.87924100512, 9783.93962050256, 4891.96981025128,
          2445.98490512564, 1222.99245256282, 611.49622628141, 305.748113140705,
          152.8740565703525, 76.43702828517625, 38.21851414258813,
          19.109257071294063, 9.554628535647032,
        ],
      });
      this.terrainLayer = this.tdtLayer(
        { type: "ter_w", tileGrid: terrainTileGrid },
        { visible: false }
      );
      this.terrainMarkLayer = this.tdtLayer(
        { type: "cta_w", tileGrid: terrainTileGrid },
        { visible: false }
      );
      this.districtLayer = this.tdtLayer({ type: "ibo_w" });
      return [
        this.vectorLayer,
        this.vectorMarkLayer,
        this.imageLayer,
        this.imageMarkLayer,
        this.terrainLayer,
        this.terrainMarkLayer,
        this.districtLayer,
      ];
    },
    tdtLayer(so = {}, lo = {}) {
      if (!so.key) {
        so.key = "d7fcef2a4ffdf0c94810504c5403c2c9";
      }
      so.url = `http://t{0-7}.tianditu.gov.cn/DataServer?T=${so.type}&x={x}&y={y}&l={z}&tk=${so.key}`;
      return new TileLayer({
        source: new XYZSource(so),
        ...lo,
      });
    },
    getAmapLayers() {
      this.vectorLayer = this.mapLayer({
        url: "http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&style=8&lang=zh_cn&size=1&scale=1",
      });
      this.imageLayer = this.mapLayer(
        {
          url: "http://webst0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&style=6",
        },
        { visible: false }
      );
      this.imageMarkLayer = this.mapLayer(
        {
          url: "http://webst0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&style=8",
        },
        { visible: false }
      );
      return [this.vectorLayer, this.imageLayer, this.imageMarkLayer];
    },
    getMapLayers() {
      this.vectorLayer = this.mapLayer({
        url: "http://cache1.arcgisonline.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}",
      });
      this.imageLayer = this.mapLayer(
        {
          url: "https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
          tileGrid,
        },
        { visible: false }
      );
      this.imageMarkLayer = this.mapLayer(
        {
          url:
            // 'https://services.arcgisonline.com/arcgis/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}',
            "http://t{0-7}.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=d7fcef2a4ffdf0c94810504c5403c2c9",
          tileGrid,
        },
        { visible: false }
      );
      this.terrainLayer = this.mapLayer(
        {
          url: "https://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}",
          tileGrid,
        },
        { visible: false }
      );
      return [
        this.vectorLayer,
        this.imageLayer,
        this.imageMarkLayer,
        this.terrainLayer,
      ];
    },
    mapLayer(so = {}, lo = {}) {
      return new TileLayer(Object.assign({ source: new XYZSource(so) }, lo));
    },
    resize() {
      const element = this.map.getTargetElement();
      let width = element.clientWidth;
      let height = element.clientHeight;
      this.timer = setInterval(() => {
        const clientWidth = element.clientWidth;
        const clientHeight = element.clientHeight;
        if (clientWidth == width && clientHeight == height) {
          return;
        }
        width = element.clientWidth;
        height = element.clientHeight;
        this.map.updateSize();
      }, 10);
    },
  },
};
</script>
<style lang="scss" scoped>
.map {
  position: relative;
  &-switcher {
    position: absolute;
    top: 40px;
    right: 5px;
    z-index: 1;
  }
  &-layer {
    position: absolute;
    top: 5px;
    right: 5px;
    z-index: 1;
  }
}
</style>
